﻿using CommonUtil;
using Communication.UDPClient;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using UDPTester.Models;

namespace UDPTester
{
    public partial class FormMain : Form
    {
        private readonly string IgnorAndReplyPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "IgnorAndReply.xml");

        private UDPClient udpClient;
        private IPEndPoint remotePoint;

        public FormMain()
        {
            InitializeComponent();
        }

        private void FormMain_Load(object sender, EventArgs e)
        {
            this.txtLocalIP.Text = Properties.Settings.Default.LocalIP;
            this.numLocalPort.Value = Properties.Settings.Default.LocalPort;
            this.txtRemoteIP.Text = Properties.Settings.Default.RemoteIP;
            this.numRemotePort.Value = Properties.Settings.Default.RemotePort;
            ReflashControlsEnable(false);

            try
            {
                GlobalVariable.IgnorAndReplyList = XmlHelper.XmlDeserializeFromFile<BindingList<IgnorAndReply>>(IgnorAndReplyPath, Encoding.UTF8);
            }
            catch
            {
                GlobalVariable.IgnorAndReplyList = new BindingList<Models.IgnorAndReply>();
            }
            ReflashButtonState();

            StartAutoSendTask();
        }

        #region 连接 

        private void btnConnect_Click(object sender, EventArgs e)
        {
            try
            {
                string LocalIP = this.txtLocalIP.Text.Trim();
                int LocalPort = (int)this.numLocalPort.Value;
                udpClient = new UDPClient(LocalIP, LocalPort);
                udpClient.UDPMessageReceived += UdpClient_UDPMessageReceived;

                string RemoteIP = this.txtRemoteIP.Text.Trim();
                int RemotePort = (int)this.numRemotePort.Value;
                remotePoint = new IPEndPoint(IPAddress.Parse(RemoteIP), RemotePort);

                ReflashControlsEnable(true);

                Properties.Settings.Default.LocalIP = LocalIP;
                Properties.Settings.Default.LocalPort = LocalPort;
                Properties.Settings.Default.RemoteIP = RemoteIP;
                Properties.Settings.Default.RemotePort = RemotePort;
                Properties.Settings.Default.Save();
            }
            catch (Exception ex)
            {
                MessageBox.Show($"连接失败:{ex.Message}");
            }
        }

        private void btnDisconnect_Click(object sender, EventArgs e)
        {
            udpClient?.CloseUDP();
            udpClient = null;
            ReflashControlsEnable(false);
            this.btnAutoSendStop_Click(null, null);
        }

        private void ReflashControlsEnable(bool enable)
        {
            this.txtLocalIP.Enabled = !enable;
            this.numLocalPort.Enabled = !enable;
            this.txtRemoteIP.Enabled = !enable;
            this.numRemotePort.Enabled = !enable;

            this.btnConnect.Enabled = !enable;
            this.btnDisconnect.Enabled = enable;

            this.groupBoxSend.Enabled = enable;
        }

        #endregion

        #region 接收

        private bool ReflashReceivedData = true;
        private bool ShowHex = true;
        private bool NotShowDetail = true;

        private void UdpClient_UDPMessageReceived(UdpStateEventArgs args)
        {
            Debug.WriteLine($"receive Length={args.buffer.Length}");


            string datestr = "";
            if (ShowHex)
            {
                datestr = ConvertHelper.ByteArrayToHexString(args.buffer);
            }
            else
            {
                datestr = Encoding.ASCII.GetString(args.buffer);
            }

            //处理自动回复
            ProcessAutoReply(datestr);


            if (!ReflashReceivedData)
            {
                return;
            }
            //判断是否要忽略显示
            if (IsIgnor(datestr))
            {
                datestr = ".";
            }
            else
            {
                //略显
                if (NotShowDetail && datestr.Length > 60)
                {
                    datestr = datestr.Substring(0, 60) + "...";
                }
            }

            //Show
            this.Invoke(new Action(() =>
            {
                DateTime now = DateTime.Now;
                string info = datestr;
                if (datestr != ".")
                {
                    info = $"\r\n[{now:HH:mm:ss.fff}][From:{args.remoteEndPoint}]({args.buffer.Length:D4}){datestr}";
                }

                this.txtReceived.Text += info;
                if (this.txtReceived.Text.Length > 80000)
                {
                    this.txtReceived.Text = "";
                }
                this.txtReceived.SelectionStart = this.txtReceived.Text.Length + 10;
                this.txtReceived.SelectionLength = 0;
                this.txtReceived.ScrollToCaret();
            }));
        }

        /// <summary>
        /// 处理自动回复
        /// </summary>
        /// <param name="datastr"></param>     
        private void ProcessAutoReply(string datastr)
        {
            foreach (IgnorAndReply ignorItem in GlobalVariable.IgnorAndReplyList)
            {
                if (ignorItem.IsAutoReply)
                {
                    //先处理OR的情况
                    bool IsMatch = false;
                    foreach (var condition in ignorItem.ConditionList)
                    {
                        if (condition.JoinType == JoinType.OR)
                        {
                            if (ConditionIsMatch(condition, datastr))
                            {
                                IsMatch = true;
                                break;
                            }
                        }
                    }

                    if (IsMatch)
                    {
                        AutoPeply(ignorItem);
                        continue;
                    }

                    //再处理AND的情况
                    bool AllMatch = true;
                    foreach (var condition in ignorItem.ConditionList)
                    {
                        if (condition.JoinType == JoinType.And)
                        {
                            if (!ConditionIsMatch(condition, datastr))
                            {
                                AllMatch = false;
                                break;
                            }
                        }
                    }
                    if (AllMatch)
                    {
                        AutoPeply(ignorItem);
                    }
                }
            }
        }

        private void AutoPeply(IgnorAndReply ignorItem)
        {
            byte[] bytes;
            if (ignorItem.ReplyType == TemplateType.Hex)
            {
                bytes = ConvertHelper.HexStringToByteArray(ignorItem.ReplyText);
            }
            else
            {
                bytes = Encoding.UTF8.GetBytes(ignorItem.ReplyText);
            }
            SendData(bytes);
        }

        /// <summary>
        /// 判断收到的文本，看是否满足忽略的条件
        /// </summary>
        /// <param name="datastr"></param>
        /// <returns></returns>
        private bool IsIgnor(string datastr)
        {
            foreach (var ignorItem in GlobalVariable.IgnorAndReplyList)
            {
                if (ignorItem.IsIgnor)
                {
                    //先处理OR的情况
                    foreach (var condition in ignorItem.ConditionList)
                    {
                        if (condition.JoinType == JoinType.OR)
                        {
                            if (ConditionIsMatch(condition, datastr))
                            {
                                return true;
                            }
                        }
                    }

                    //再处理AND的情况
                    bool AllMatch = true;
                    foreach (var condition in ignorItem.ConditionList)
                    {
                        if (condition.JoinType == JoinType.And)
                        {
                            if (!ConditionIsMatch(condition, datastr))
                            {
                                AllMatch = false;
                                break;
                            }
                        }
                    }
                    if (AllMatch)
                    {
                        return true;
                    }
                }
            }

            return false;
        }

        /// <summary>
        /// 判断是否满足条件
        /// </summary>
        /// <param name="condition">条件</param>     
        private bool ConditionIsMatch(Condition condition, string datastr)
        {
            bool match = false;
            switch (condition.ConditionType)
            {
                case ConditionType.Equal:
                    match = datastr == condition.Content;
                    break;

                case ConditionType.StartWith:
                    match = datastr.StartsWith(condition.Content);
                    break;

                case ConditionType.EndWith:
                    match = datastr.EndsWith(condition.Content);
                    break;

                case ConditionType.Contain:
                    match = datastr.Contains(condition.Content);
                    break;
                case ConditionType.Regular:
                    match = Regex.IsMatch(datastr, condition.Content);
                    break;
            }

            return match;
        }

        private void btnReflashStart_Click(object sender, EventArgs e)
        {
            ReflashReceivedData = true;
            btnReflashStart.Enabled = false;
            btnReflashStop.Enabled = true;
        }

        private void btnReflashStop_Click(object sender, EventArgs e)
        {
            ReflashReceivedData = false;
            btnReflashStart.Enabled = true;
            btnReflashStop.Enabled = false;
        }

        private void btnCopy_Click(object sender, EventArgs e)
        {
            this.txtReceived.SelectAll();
            this.txtReceived.Copy();

            MessageBox.Show("已经复制到粘贴板");
        }

        private void btnClear_Click(object sender, EventArgs e)
        {
            this.txtReceived.Text = "";
        }

        private void radShowHex_CheckedChanged(object sender, EventArgs e)
        {
            ShowHex = true;
        }

        private void radShowString_CheckedChanged(object sender, EventArgs e)
        {
            ShowHex = false;
        }

        private void checkNotShowDetail_CheckedChanged(object sender, EventArgs e)
        {
            NotShowDetail = this.checkNotShowDetail.Checked;
        }

        private void btnIgnorList_Click(object sender, EventArgs e)
        {
            new FormIgnorAndReply().ShowDialog();
            ReflashButtonState();
        }

        #endregion

        #region 发送

        private void btnSelStringTemplate_Click(object sender, EventArgs e)
        {
            FormTemplate formTemplate = new FormTemplate();
            if (formTemplate.ShowDialog() == DialogResult.OK)
            {
                this.txtSendString.Text = formTemplate.SelectedString;
            }
        }
        private void btnSendString_Click(object sender, EventArgs e)
        {
            string sendstr = this.txtSendString.Text.Trim();

            if (radSendHex.Checked)
            {
                try
                {
                    if (sendstr.Length > 1)
                    {                       
                        if (chkAutoCRC.Checked)
                        {
                            sendstr += " 00 00";
                        }

                        var bytes = ConvertHelper.HexStringToByteArray(sendstr);

                        if(chkAutoCRC.Checked)
                        {
                            bytes = ConvertHelper.CalCRC16a(bytes);
                        }

                        SendData(bytes);
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"错误：{ex.Message}");
                    return;
                }
            }
            else
            {
                if (sendstr.Length > 0)
                {
                    var bytes = Encoding.ASCII.GetBytes(sendstr);
                    SendData(bytes);
                }
            }
        }

        private void SendData(byte[] buffer)
        {
            if (udpClient != null)
            {
                try
                {
                    udpClient.SendData(remotePoint, buffer);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }

                this.Invoke(new Action(() =>
                {
                    var datestr = ConvertHelper.ByteArrayToHexString(buffer);
                    DateTime now = DateTime.Now;
                    string info = $"\r\n[{now:hh:mm:ss.fff}][TO:{remotePoint}]({buffer.Length:D4}){datestr}";

                    this.txtSent.Text += info;
                    if (this.txtSent.Text.Length > 80000)
                    {
                        this.txtSent.Text = "";
                    }
                    this.txtSent.SelectionStart = this.txtSent.Text.Length + 10;
                    this.txtSent.SelectionLength = 0;
                    this.txtSent.ScrollToCaret();
                }));
            }
        }

        private void btnClearSent_Click(object sender, EventArgs e)
        {
            this.txtSent.Text = "";
        }

        private bool AutoSend = false;
        private int AutoSendTicks = 1000;
        private byte[] AutoSendData;

        private void StartAutoSendTask()
        {
            Task.Run(() =>
            {
                while (true)
                {
                    if (AutoSend)
                    {
                        SendData(AutoSendData);
                    }
                    Thread.Sleep(AutoSendTicks);
                }
            });
        }

        private void btnAutoSendStart_Click(object sender, EventArgs e)
        {
            try
            {
                string autoSendStr = this.txtAutoSendHex.Text.Trim();

                if (radAutoSendHex.Checked)
                {
                    if (autoSendStr.Length > 1)
                    {
                        AutoSendData = ConvertHelper.HexStringToByteArray(autoSendStr);
                        AutoSendStart();
                    }
                }
                else
                {
                    if (autoSendStr.Length > 0)
                    {
                        AutoSendData = Encoding.UTF8.GetBytes(autoSendStr);
                        AutoSendStart();
                    }
                }

            }
            catch (Exception ex)
            {
                AutoSend = false;
                MessageBox.Show($"错误：{ex.Message}");
                return;
            }
        }

        private void AutoSendStart()
        {
            AutoSend = true;
            this.btnAutoSendStart.Enabled = false;
            this.btnAutoSendStop.Enabled = true;
            this.txtAutoSendHex.Enabled = false;
            this.radAutoSendHex.Enabled = false;
            this.radAutoSendString.Enabled = false;
        }

        private void btnAutoSendStop_Click(object sender, EventArgs e)
        {
            AutoSend = false;
            this.btnAutoSendStart.Enabled = true;
            this.btnAutoSendStop.Enabled = false;
            this.txtAutoSendHex.Enabled = true;
            this.radAutoSendHex.Enabled = true;
            this.radAutoSendString.Enabled = true;
        }

        private void numAutoSendTicks_ValueChanged(object sender, EventArgs e)
        {
            AutoSendTicks = (int)this.numAutoSendTicks.Value;
        }

        private void btnSelAutoTemplate_Click(object sender, EventArgs e)
        {
            FormTemplate formTemplate = new FormTemplate();
            if (formTemplate.ShowDialog() == DialogResult.OK)
            {
                this.txtAutoSendHex.Text = formTemplate.SelectedString;
            }
        }

        #endregion

        private void btnTools_Click(object sender, EventArgs e)
        {
            new FormTools().Show();
        }

        private void btnAbout_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            new FormAbout().ShowDialog();
        }

        private void ReflashButtonState()
        {
            bool IsUsing = false;
            foreach(var item in GlobalVariable.IgnorAndReplyList)
            {
                if(item.IsIgnor||item.IsAutoReply)
                {
                    IsUsing = true;
                    break;
                }
            }

            if(IsUsing)
            {
                btnIgnorAndReply.BackColor = Color.Green;
                btnIgnorAndReply.ForeColor = Color.White;
            }
            else
            {
                btnIgnorAndReply.BackColor = Color.LightGray;
                btnIgnorAndReply.ForeColor = Color.Black;
            }
        }

        private void radSendHex_CheckedChanged(object sender, EventArgs e)
        {
            this.chkAutoCRC.Enabled=this.radSendHex.Checked;
            if (this.radSendString.Checked)
                this.chkAutoCRC.Checked = false;
        }
    }
}